﻿using nhCore;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using nhCore.db;

namespace envG
{
    public partial class FrmWindRose : Form
    {
        private Station EnvState { get; set; }
        private DataGridView Dgv { get; set; }
        private Dictionary<int, int> DicCellIndex { get; set; }

        private string[] Fw8 { get; set; } = { "北", "东北", "东", "东南", "南", "西南", "西", "西北" };
        private string[] Fw16 { get; set; } = { "北", "北东北", "东北", "东东北", "东", "东东南", "东南", "南东南", "南", "南西南", "西南", "西西南", "西", "西西北", "西北", "北西北" };

        /// <summary>
        /// 各个方向的风速，0-7或0-15对应方位
        /// </summary>
        private Dictionary<int, List<double>> FsData { get; set; } = new Dictionary<int, List<double>>();
        /// <summary>
        /// 各个风向的频次，0-7或0-15对应方位
        /// </summary>
        private Dictionary<int, int> FxData { get; set; } = new Dictionary<int, int>();
        /// <summary>
        /// 静风频次
        /// </summary>
        private int StillWind { get; set; } = 0;
        /// <summary>
        /// 静风比例
        /// </summary>
        private double StillWindRatio { get; set; } = 0;

        private bool IsCanResize { get; set; } = true;
        private bool IsWindowLoaded { get; set; } = false;

        public FrmWindRose(Station sensor, DataGridView dgv)
        {
            EnvState = sensor;
            Dgv = dgv;
            DicCellIndex = Dgv.Tag as Dictionary<int, int>;
            InitializeComponent();
        }

        private void FrmWindRose_Load(object sender, EventArgs e)
        {
            foreach (var c in EnvState.ElementConfigs)
            {
                if (c.ElementType.ToLower() == "fengsu")
                {
                    CbFs.Items.Add(c);
                }
                else if (c.ElementType.ToLower() == "fengxiang")
                {
                    CbFx.Items.Add(c);
                }
            }

            if (CbFx.Items.Count == 0 || CbFs.Items.Count == 0)
            {
                MessageBox.Show("时间、风速、风向信息缺失，无法绘制风玫瑰。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                DialogResult = DialogResult.Cancel;
                return;
            }
            CbFx.SelectedIndex = 0;
            CbFs.SelectedIndex = 0;
            CbFw.SelectedIndex = 1;
        }

        private void FrmWindRose_Shown(object sender, EventArgs e)
        {
            IsWindowLoaded = true;
            LoadingData();
            RePaint();
        }

        /// <summary>
        /// 风速风向数据保存到对应字典
        /// </summary>
        private void LoadingData()
        {
            FxData.Clear();
            FsData.Clear();

            int fw = CbFw.SelectedIndex == 0 ? 8 : 16;
            for (int i = 0; i < fw; i++)
            {
                FsData.Add(i, new List<double>());
                FxData.Add(i, 0);
            }

            int fsIndex = DicCellIndex[(int)(CbFs.SelectedItem as ElementConfig).StationReg];
            int fxIndex = DicCellIndex[(int)(CbFx.SelectedItem as ElementConfig).StationReg];
            double baseSum = CbFw.SelectedIndex == 0 ? 45 : 22.5;
            int offest = (int)(baseSum / 2);
            int fwIndex;
            foreach (DataGridViewRow row in Dgv.Rows)
            {
                double? fs = row.Cells[fsIndex].Value as double?;
                double? fx = row.Cells[fxIndex].Value as double?;
                if (fs.HasValue && fx.HasValue)
                {
                    if (fs == 0)
                    {
                        StillWind += 1;
                    }
                    if (fs.HasValue && fs > 0 && fx >= 0)//有风速，且不是无效数据
                    {
                        fwIndex = (int)((fx + offest) % 360 / baseSum);
                        FxData[fwIndex] += 1;
                        FsData[fwIndex].Add((double)fs);
                    }
                }
            }
        }

        private void RePaint()
        {
            Dictionary<int, double> DicFsAvg = new Dictionary<int, double>();

            foreach (var key in FsData.Keys)//统计平均风速
            {
                List<double> values = FsData[key];
                double value = 0;
                if (values.Count > 0)
                {
                    value = values.Average();
                }
                DicFsAvg.Add(key, value);
            }
            Dictionary<int, double> DicFxRatio = new Dictionary<int, double>();
            int sum = FxData.Values.Sum() + StillWind;
            StillWindRatio = (double)StillWind / sum;
            foreach (var key in FsData.Keys)//统计风向比率
            {
                double value = (double)FxData[key] / sum;
                DicFxRatio.Add(key, value);
            }

            int Size = Math.Min(Math.Max(PlCanvas.Width, PlCanvas.Height) / 2, Math.Min(PlCanvas.Width, PlCanvas.Height));

            var fp = MakeAxis(Size, Size, $"风向频率玫瑰(%) 静风{StillWindRatio:P1}", Color.OrangeRed, DicFxRatio, "P1");
            var fs = MakeAxis(Size, Size, "风速玫瑰图(m/s)", Color.Green, DicFsAvg, "N");
            var bg = new Bitmap(PlCanvas.Width, PlCanvas.Height);
            var g = Graphics.FromImage(bg);
            g.Clear(Color.White);
            if (PlCanvas.Height > PlCanvas.Width)
            {

                var Yindex = (PlCanvas.Height - 2 * Size) / 2;
                var Xindex = (PlCanvas.Width - Size) / 2;
                g.DrawImage(fp, Xindex, Yindex);
                g.DrawImage(fs, Xindex, Yindex + Size);
            }
            else
            {

                var Yindex = (PlCanvas.Height - Size) / 2;
                var Xindex = (PlCanvas.Width - 2 * Size) / 2;
                g.DrawImage(fp, Xindex, Yindex);
                g.DrawImage(fs, Xindex + Size, Yindex);
            }
            PlCanvas.BackgroundImage = bg;
        }

        /// <summary>
        /// 绘制坐标及数据
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="title"></param>
        /// <param name="mainColor"></param>
        /// <param name="data">统计后的风速或风向数据</param>
        /// <param name="valueFormat"></param>
        /// <returns></returns>
        private Bitmap MakeAxis(int width, int height, string title, Color mainColor, Dictionary<int, double> data, string valueFormat)
        {
            Bitmap canvas = new Bitmap(width, height);
            int margin = 35;
            int maxSize = Math.Min(canvas.Width - margin * 4, canvas.Height - margin * 2);
            int count = 5;
            Graphics g = Graphics.FromImage(canvas);
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
            g.TranslateTransform(canvas.Width / 2, canvas.Height / 2);
            Pen p = new Pen(Color.Gray)
            {
                DashStyle = DashStyle.Dot
            };
            Brush b = Brushes.Black;
            int largeR = maxSize / 2;
            Font titleFont = new Font(Font.Name, 12);
            g.DrawString(title, titleFont, b, -(g.MeasureString(title, titleFont).Width / 2), -(largeR + margin + titleFont.Height));

            double angleStep = 360 / data.Keys.Count;
            double angle = 0;
            PointF current = new PointF();

            LinkedList<PointF> points = new LinkedList<PointF>();

            double maxValue = data.Values.Max() * 1.1;
            for (int i = 1; i <= count; i++)
            {
                int r = (maxSize / count) * i / 2;
                g.DrawEllipse(p, -r, -r, 2 * r, 2 * r);//刻度圈
            }
            foreach (int key in data.Keys)
            {
                double value = data[key];
                PointF valuePoint = GetEndPoint(angle, largeR * value / maxValue);
                PointF valueTextPoint = valuePoint;
                points.AddLast(valuePoint);
                string txt = $"{data[key].ToString(valueFormat)}";
                if (valuePoint.Y < 0)
                {
                    valueTextPoint.Y -= g.MeasureString(txt, Font).Height;
                }

                if (valuePoint.X < 0)
                {
                    valueTextPoint.X -= g.MeasureString(txt, Font).Width;
                }
                g.DrawString(txt, Font, new SolidBrush(mainColor), valueTextPoint);

                PointF endPoint = GetEndPoint(angle, largeR);
                g.DrawLine(p, current, endPoint);
                //标签文字
                PointF txtPoint = GetEndPoint(angle, largeR + 6);
                string Direction = CbFw.SelectedIndex == 0 ? Fw8[key] : Fw16[key];//中文方向
                if (endPoint.Y < 0)
                {
                    txtPoint.Y -= g.MeasureString(Direction, Font).Height;
                }

                if (endPoint.X < 0 && endPoint.Y != 0)
                {
                    txtPoint.X -= g.MeasureString(Direction, Font).Width;
                }

                g.DrawString(Direction, Font, b, txtPoint);
                angle += angleStep;
            }
            var fillBrush = new SolidBrush(Color.FromArgb(120, mainColor));// 半透明填充色
            g.FillPolygon(fillBrush, points.ToArray());// 填充
            g.DrawPolygon(new Pen(mainColor), points.ToArray());// 描边
            return canvas;
        }

        /// <summary>
        /// 角度半径转为坐标
        /// </summary>
        /// <param name="angle">角度</param>
        /// <param name="r">半径</param>
        /// <returns>坐标</returns>
        private PointF GetEndPoint(double angle, double r)
        {
            return new PointF()
            {
                Y = (float)(-Math.Cos(angle * Math.PI / 180) * r),
                X = (float)(Math.Sin(angle * Math.PI / 180) * r)
            };
        }

        private void BtnSave_Click(object sender, EventArgs e)
        {
            var d = new SaveFileDialog
            {
                Filter = "Jpeg|*.jpg",
                FileName = "风玫瑰图"
            };
            if (d.ShowDialog() == DialogResult.OK)
            {
                PlCanvas.BackgroundImage.Save(d.FileName, ImageFormat.Jpeg);
            }
        }

        private void FrmWindRose_ResizeBegin(object sender, EventArgs e)
        {
            IsCanResize = false;
        }

        private void FrmWindRose_ResizeEnd(object sender, EventArgs e)
        {
            IsCanResize = true;
            RePaint();
        }

        private void CbFw_Fs_Fx_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (IsWindowLoaded)
            {
                LoadingData();
                RePaint();
            }
        }
    }
}
